package com.angle.im.server.utils;

import com.angle.im.common.exception.TokenException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangwei
 * @date 2019/4/15 19:19
 * @desc
 */
public class JWTUtils {

    private static RSAPrivateKey priKey;
    private static RSAPublicKey pubKey;

    public static final String PLATFORM = "platform";

    private static class SingletonHolder {
        private static final JWTUtils INSTANCE = new JWTUtils();
    }

    public synchronized static JWTUtils getInstance(String modulus, String privateExponent, String publicExponent) {
        if (priKey == null && pubKey == null) {
            priKey = RSAUtils.getPrivateKey(modulus, privateExponent);
            pubKey = RSAUtils.getPublicKey(modulus, publicExponent);
        }
        return SingletonHolder.INSTANCE;
    }

    public synchronized static void reload(String modulus, String privateExponent, String publicExponent) {
        priKey = RSAUtils.getPrivateKey(modulus, privateExponent);
        pubKey = RSAUtils.getPublicKey(modulus, publicExponent);
    }

    public synchronized static JWTUtils getInstance() {
        if (priKey == null && pubKey == null) {
            priKey = RSAUtils.getPrivateKey(RSAUtils.modulus, RSAUtils.private_exponent);
            pubKey = RSAUtils.getPublicKey(RSAUtils.modulus, RSAUtils.public_exponent);
        }
        return SingletonHolder.INSTANCE;
    }

    /**
     * 获取Token
     *
     * @param userId  用户ID
     * @param minutes 失效时间，单位分钟
     * @return
     */
    public String getToken(String platform, String userId, int minutes) {
        long endTime = System.currentTimeMillis() + 1000 * 60 * minutes;
        Map<String,Object> claims = new HashMap<>(1);
        claims.put(PLATFORM,platform);
        return Jwts.builder().setSubject(userId).setExpiration(new Date(endTime)).addClaims(claims)
                .signWith(SignatureAlgorithm.RS512, priKey).compact();
    }

    /**
     * 检查Token是否合法
     *
     * @param token
     * @return String 用户id
     */
    public void checkToken(String token) {
        try {
            Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token).getBody();
        } catch (ExpiredJwtException e) {
            // 在解析JWT字符串时，如果‘过期时间字段’已经早于当前时间，将会抛出ExpiredJwtException异常，说明本次请求已经失效
            throw new TokenException("token已过期");
        } catch (Exception e) {
            throw new TokenException("非法请求");
        }
    }

    /**
     * 获取用户id
     *
     * @param token
     * @return String 用户id
     */
    public String getSubject(String token) {
        return getClaims(token).getSubject();
    }

    /**
     * 解析token,获取Claims
     * @param token
     * @return
     */
    public Claims getClaims(String token){
        try {
            return Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token).getBody();
        } catch (ExpiredJwtException e) {
            throw new TokenException("token已过期");
        } catch (Exception e) {
            e.printStackTrace();
            throw new TokenException("非法请求");
        }
    }
    /**
     * 获取平台码
     *
     * @param token
     * @return String 用户id
     */
    public String getPlatform(String token) {
        try {
            return getClaims(token).get(PLATFORM, String.class);
        } catch (ExpiredJwtException e) {
            throw new TokenException("token已过期");
        } catch (Exception e) {
            e.printStackTrace();
            throw new TokenException("非法请求");
        }
    }

}
